#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/sem.h>  

#include "frcomm.h"

union semun  
{  
    int val;
    struct semid_ds *buf;  
    unsigned short *arry;  
};

static int set_semvalue(int i_sem_id)  
{  
    //用于初始化信号量，在使用信号量前必须这样做  
    union semun sem_union;  
  
    sem_union.val = 1;  
    if(semctl(i_sem_id, 0, SETVAL, sem_union) == -1)  
        return 0;  
    return 1;  
}

int frsem_create(char *p_file)
{
    int i_key = 0, i_sem_id = 0;

    if (p_file == NULL || *p_file == '\0')
        return -1;

    i_key = ftok(p_file, 1);
    if (i_key < 0)
        return -1;
    
    i_sem_id = semget((key_t)i_key, 1, IPC_EXCL | IPC_CREAT);
    if (i_sem_id < 0)
        return -1;
    
    if (!set_semvalue(i_sem_id))
        return -1;
    
    return i_sem_id;
}

int frsem_get(char *p_file)
{
    int i_key = 0;

    if (p_file == NULL || *p_file == '\0')
        return -1;

    i_key = ftok(p_file, 1);
    if (i_key < 0)
        return -1;
    
    return semget((key_t)i_key, 0, 0);
}

int frsemaphore_lock(int i_sem_id)
{
    //对信号量做减1操作，即等待P（sv）  
    struct sembuf sem_b;

    if (i_sem_id <= 0)
        return FR_FAIL;
    
    sem_b.sem_num = 0;  
    sem_b.sem_op = -1;//P()  
    sem_b.sem_flg = SEM_UNDO;  
    if(semop(i_sem_id, &sem_b, 1) == -1)  
    {  
        fprintf(stderr, "semaphore_p failed\n");  
        return FR_FAIL;
    }  
    return FR_SUCC;
}

int frsemaphore_unlock(int i_sem_id)  
{  
    //这是一个释放操作，它使信号量变为可用，即发送信号V（sv）  
    struct sembuf sem_b;

    if (i_sem_id <= 0)
        return FR_FAIL;

    sem_b.sem_num = 0;  
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;  
    if(semop(i_sem_id, &sem_b, 1) == -1) 
    {  
        fprintf(stderr, "semaphore_v failed\n");  
        return FR_FAIL;
    }  
    return FR_SUCC;
}  

void frsem_free(int i_sem_id)
{  
    //删除信号量  
    union semun sem_union;  
  
    semctl(i_sem_id, 0, IPC_RMID, sem_union);
}
